回顧前幾天的學習筆記,我們現在已經知道
在前四天打好基礎後,今天的學習筆記中,將會介紹
小提醒:今天的程式碼都可以在 demo-pod 上找到唷
在開始將我們 前天打造的 Docker Container 運行在 Kubernetes 之前,我們需要先認識Pod
。
Kubernetes 上會運行很多個不同種類型的應用服務(applications),而一個 Pod 在Kubernetes世界中就相當於一個application。
Pod有以下特點,
在這裡我們會以昨天打造好的 docker image 來做示範,若讀者有自己的Docker Image,在以下的指令中都可以替換成自己的 Docker Image。
關於示範的 Docker Image,可以參考 [Day 3] 打造你的Docker containers
以下 my-first-pod.yaml 是我們今天會用到的 yaml 檔,
# my-first-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: my-pod
labels:
app: webserver
spec:
containers:
- name: pod-demo
image: zxcvbnius/docker-demo
ports:
- containerPort: 3000
apiVersion
apiVersion 是代表目前 Kubernetes 中該元件的版本號。以上述的例子 Pod
是 v1
,而 v1也是目前Kubernetes中核心的版本號
。在日後也會陸續看到 betav1
, v1alpha1
等版本號,更多 Kubernetes API 的版本號,可至 官網 API versioning查看。
metadata
在 metadata 中,有三個重要的 Key,分別是 name
, labels
, annotations
。
metadata.name
的欄位指定這個 Pod 的名稱,這裡 Pod 的名稱就是 my-podmetadata.labels
是 Kubernetes 的是核心的元件之一,Kubernetes 會透過 Label Selector
將Pod分群管理。在之後 [Day 10] Kubernetes世界不可缺少的 - Labels 學習筆記中,將會詳細介紹 Labels 的功能。annotations 通常是使用者任意自定義的附加資訊
,提供外部進行查詢使用,像是版本號,發布日期等等。spec
最後 spec 的部分則是定義 container,在這個範例中,一個 Pod 只運行一個 container。
該 container 有哪些 port number 是允許外部資源存取
,而在這裡我們只允許container中的port 3000對外開放。在了解 my-first-pod.yaml 每一行在做什麼事情之後,我們可以使用 kubectl create 指令在 Kubernetes Cluster 中建立 Pod 物件
,
這樣,就建立好 my-app 這個 Pod 了。可以用 kubectl get pods 查看目前 pods 的狀態
,
可以看到 ContainerCreating
的狀態,如果再等一下就會看到狀態變為 Running
,代表 Pod 已經正常開始跑了。
我們也可以用 kubectl describe 指令可以看到更多關於 my-pod 這個物件的資訊
,包含我們設置的 Pod Name,labels, 以及這個 pod 的歷史狀態,更多的 log 在 describe-my-pod.log
$ kubectl describe pods my-pod
Name: my-pod
Namespace: default
.....
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 7m default-scheduler Successfully assigned my-pod to minikube
Normal SuccessfulMountVolume 7m kubelet, minikube MountVolume.SetUp succeeded for volume "default-token-wxjzb"
Normal Pulling 7m kubelet, minikube pulling image "zxcvbnius/docker-demo"
Normal Pulled 7m kubelet, minikube Successfully pulled image "zxcvbnius/docker-demo"
Normal Created 7m kubelet, minikube Created container
Normal Started 7m kubelet, minikube Started container
在 my-pod 中,有個 container 運行 API server, port number 3000
。然而,我們要怎麼與他做互動呢?常見存取 Pod 資源的方法有兩種,
kubectl 提供一個指令 port-forward 能將pod中的某個port number,與本機端的port做mapping
。在今天最後 常用kubectl指令 章節中會提到更多關於 kubectl port-forward
指令的介紹,
$ kubectl port-forward my-pod 8000:3000
Forwarding from 127.0.0.1:8000 -> 3000
看到 Forwarding from 127.0.0.1:8000 -> 3000
代表 port-forward 成功,現在可以在本機端的瀏覽器打開 http://127.0.0.1:8000 ,就可以看到我們運行的 API Server 吐回來的訊息 Hello World!
。
在 之後的學習筆記 中也會針對 Kubernetes 中的 Service 詳細介紹。而在這章節,我們則是透過 kubectl expose 指令
幫我們在Kubernetes建立一個 Service 物件。
kubectl port-forward 是將 pod 的 port mapping 到本機端上,而 kubectl expose 則是將 pod 的 port 與 Kubernetes Cluster 的 port number 做 mapping。
我們先可以使用 minikube status 查看目前 minikube-vm 是使用本機端哪個內部網址
。
接著輸入 kubectl expose
指令,創建一個名為 my-pod-service
的 Service 物件
$ kubectl expose pod my-pod --type=NodePort --name=my-pod-service
service "my-pod-service" exposed
這時我們可以再輸入 kubectl get services
查看目前運行的 Services 有哪些
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 9h
my-pod-service NodePort 10.97.118.40 <none> 3000:30427/TCP 1m
可以看到 my-pod-service
將 my-pod
的 port number 30003 與 minikube-vm 上的 port number 30427 做 mapping。接著可以使用 minukube service
的指令快速找到 my-pod-service 的 url
$ minikube service my-pod-service --url
http://192.168.99.104:30427
這時再從你的本機端上的瀏覽器打開 http://192.168.99.104:30427 ,就可以看到 hello world
的字樣。
Kubernetes Cluster 內部會有一套網路系統,會替每個 Pod 建立一個 Cluster IP,這個 IP 是由 Kubernetes 內部隨機產生的
。這個 Cluster IP 只有Cluster內部資源可以使用;外部資源是無法透過 Cluster IP 與 Pods 互動,所以我們需要再建立一個 Service 元件作為一個橋樑,讓 Cluster 以外的服務也可以與 Pod 做互動。在kubectl get services
可以看到TYPE
,CLUSTER-IP
,EXTERNAL-IP
,在之後 [Day 9] 如何讓外部服務與pods的溝通管道 - Services 會再詳細介紹。
以下列出幾種我們常用到的指令,
$ kubectl get pods
如果加上--show-all
,則會顯示所有 Pods
$ kubectl get pods --show-all
$ kubectl describe pod <pod>
$ kubectl expose pod <pod> --port=<port> --name=<service-name>
$ kubectl port-forward <pod> <external-port>:<pod-port>
kubectl attach
這個指令$ kubectl attach <pod> -i
$ kubectl exec <pod> -- <command>
如果還記得 第三天 介紹到的Docker Container,會記得在 my-pod 的/app 資料夾底下有 API Server 的原始程式碼與 Dockerfile
,我們可以用 ls 列出 /app 資料夾底下的所有檔案
,如下圖所示
$ kubectl label pods <pod> <label-key>=<label-value>
可以先用 kubectl get pod --show-labels
查看目前 my-pod
有哪些 labels,
$ kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
my-pod 1/1 Running 0 14h app=webserver
如果我們想要新增 labels
,可以輸入以下指令
$ kubectl label pods my-pod version=latest
pod "my-pod" labeled
再次用 kubectl get pod --show-labels
查看,可以發現,LABELS
欄位多了一個 version
$ kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
my-pod 1/1 Running 0 14h app=webserver,version=latest
在未來學習筆記中 [Day 10] Kubernetes 世界不可缺少的 - Labels 有更多關於 Labels 的介紹。
alpine 提供非常輕量級的 Docker Image,大小只有 5MB 上下。可以藉由在 alpine下 指令,在 Kubernetes Cluster 中與其他 Pods 互動,非常適合用來 debug。以下面指令為例,在輸入下述指令後,我們就可以進到 alpine 的 shell。
$ kubectl run -i --tty alpine --image=alpine --restart=Never -- sh
是否還記得我們今天提到,
在 Kubernetes Cluster 中,會給每個 Pod 一個 Cluster IP 且只有在 Cluster 裡才可以存取
。而我們可以透過 alpine 在 Kubernetes Cluster 中訪問其他 Pods。
可以用 kubectl describe
去查 Pod 目前 Cluster IP,以my-pod
為例,目前的cluster ip是 172.17.0.4
$ kubectl describe pod my-pod
Name: my-pod
Namespace: default
Node: minikube/192.168.99.104
....
Status: Running
IP: 172.17.0.4
這時我們可以用 curl 指令去訪問Pod中container跑在port number 3000的API service
。不過我們需要先在 alpine 中安裝 curl
套件。
$ apk add --no-cache curl
安裝完之後,我們可以輸入 curl http://172.17.0.4:3000
存取成功後,會看到 Hello World!
字串
今天介紹 kubectl 常用指令以外,也認識了 Kubernetes 的第一個元件,Pod。之後的學習筆記中,會分享當有多個 Pods 同時在 Kubernetes Cluster 中時,我們會如何去管理、擴張以及確保每個 Pod 目前的運行狀態
。
依舊歡迎大家給予建議與討論,如果能按個讚給些鼓勵也是很開心唷 : )
感謝 @Samina Fu 網友的提醒,文中指令介紹應為 $ kubectl port-forward <pod> <external-port>:<pod-port>
您好!感謝您的這一系列文章,很詳盡,學習到很多。
關於上述中$ kubectl port-forward <port> <external-port>:<pod-port>
的部分,<port>
應該改為 <pod>
。
稍微看了一下 kubectl port-forward -h
的內容所得到的資訊。
謝謝
Hi @Samina Fu
哈很開心也很謝謝您的支持!是 <pod>
沒錯,已修正!
真的非常感謝你!
請問一下, 我跑 kubectl create -f my-first-pod.yaml 這句時報了以下的錯誤, 是什麼原因呢? 謝謝
[root@minikube ~]# kubectl create -f my-first-pod.yaml
error: the path "my-first-pod.yaml" does not exist
我找到原因了, 原本要有這個檔案才可以跑, 還以為是利用這個指令去生成
沒錯 XD
「my-pod-service 將 my-pod 的 port number 30003 與 minikube-vm 上的 port number 30427 做 mapping」的30003應該是3000
安裝 curl 套件失敗
想知道原因
你run起來的pod 預設都是使用k8s 提供的core-dns位置
快速的解法 vi /etc/resolv.conf
修改如下應該就可以成功